package com.uvnos4j.matilda.security.config;

import com.uvnos4j.matilda.commons.utils.Const;
import com.uvnos4j.matilda.security.callback.CustomAccessDeniedHandler;
import com.uvnos4j.matilda.security.callback.CustomAuthenticationFailureHandler;
import com.uvnos4j.matilda.security.callback.CustomAuthenticationSuccessHandler;
import com.uvnos4j.matilda.security.service.UserDetailsServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

/**
 * Web 安全配置
 * <p>
 * Description:Web 安全配置 prePostEnabled :决定Spring Security的前注解是否可用
 * [@PreAuthorize,@PostAuthorize,..] secureEnabled : 决定是否Spring Security的保障注解 [@Secured]
 * 是否可用 jsr250Enabled ：决定 JSR-250 annotations 注解[@RolesAllowed..] 是否可用.
 * </p>
 *
 * @author Guo.wl
 * @version v1.0.0
 * @since 2020-03-25 23:34:49
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    @Override
    public UserDetailsService userDetailsService() {
        return new UserDetailsServiceImpl();
    }

    /**
     * @return 配置加密方式
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setHideUserNotFoundExceptions(false);
        provider.setUserDetailsService(userDetailsService());
        provider.setPasswordEncoder(passwordEncoder());
        return provider;
    }

    // @Override
    // protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    // auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
    // }

    @Bean
    public AuthenticationFailureHandler authenticationFailureHandler() {
        return new CustomAuthenticationFailureHandler();
    }

    @Bean
    public AuthenticationSuccessHandler authenticationSuccessHandler() {
        return new CustomAuthenticationSuccessHandler();
    }

    @Bean
    public AccessDeniedHandler accessDeniedHandler() {
        return new CustomAccessDeniedHandler();
    }

    /**
     * 静态资源设置
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/app/**", "/lib/**", "/favicon*", "/captcha*");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling().and().headers().frameOptions().disable() // 解决 in a frame because it set 'X-Frame-Options' to 'DENY' 问题

                // .and()
                // .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)

                .and().authorizeRequests().antMatchers(HttpMethod.GET, Const.AUTH_LOGIN_URL).permitAll().anyRequest()
                .authenticated()

                .and().formLogin().loginPage(Const.AUTH_LOGIN_URL)
                // 登录POST请求路径
                .loginProcessingUrl(Const.AUTH_LOGIN_PROCESSING_URL)
                // 登录用户名、密码参数
                .usernameParameter(Const.AUTH_USERNAME_PARAMETER).passwordParameter(Const.AUTH_PASSWORD_PARAMETER)
                .failureHandler(authenticationFailureHandler()).successHandler(authenticationSuccessHandler())
                // .defaultSuccessUrl("/index")// 默认登录成功页面

                .and().logout().logoutUrl(Const.AUTH_LOGOUT_URL)

                .and().csrf().disable();

        //异常处理
        http.exceptionHandling().accessDeniedHandler(accessDeniedHandler());
    }

}